#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtSerialPort/QSerialPort>
#include <QTimer>
#include <QModbusClient>
#include <QModbusDataUnit>
#include <QSpinBox>
#include <QTimeEdit>
#include <QLabel>

#define READ_PROTECT_ADDR       0x100

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private:
    Ui::Widget *ui;
    QModbusClient *modbusDevice = nullptr;
    QTimer m_serialPortTimer;
    QTimer m_autoReadTimer;
    QList<QPair<QString,QSerialPort::BaudRate>> m_baudRateList =
        {   {"4800", QSerialPort::Baud4800},
            {"9600", QSerialPort::Baud9600},
            {"19200", QSerialPort::Baud19200},
            {"57600", QSerialPort::Baud57600},
            {"115200", QSerialPort::Baud115200},
        };
    QList<QPair<QString,QSerialPort::Parity>> m_parityList =
        {   {"No",QSerialPort::NoParity},
            {"Even",QSerialPort::EvenParity},
            {"Odd",QSerialPort::OddParity},
        };

public:
    enum modbus_dataTypes
    {
        discrete_inputs,
        coils,
        input_registers,
        holding_registers,
    };
    Q_ENUM(modbus_dataTypes)

    enum coils_item
    {
        read_protect = 0x100,
    };
    Q_ENUM(coils_item)

    enum discrete_inputs_item
    {
        ERR_LOW_TEMP,
        ERR_HIGH_TEMP,
        ERR_NO_FLOW,
        ERR_ORP,
        ERR_POWER,
        ERR_PH,
        ERR_WIFI,
        ERR_PH_SENSOR,
        ERR_ORP_SENSOR,
        ERR_POWER_COM,
        ERR_CL_MODULE,
        ERR_TDS_MODULE,
        ERR_ACID_PUMP,
        ERR_GAS_SW,
        ALARM_ACID_TANK = 0x30,
        ALARM_ADD_SALT,
        ALARM_REPLACE_SENSOR,
        ALARM_CALIBRATE_SENSOR,
    };
    Q_ENUM(discrete_inputs_item)

    enum input_registers_item
    {
        ORP = 0,
        PH,
        TDS,
        WATER_TEMP,
        CHASSIS_TEMP,
        OUTPUT,
        QUALITY,
        CHIP_SIZE,
        SJ,
        SI,
        SV,
        I,
        U,
        SOFT_VER_MAIN,    // 软件主版本号
        SOFT_VER_SUB,     // 软件子版本号
        PRODUCT_TYPE,      // 产品类型版本
        PRODUCT_CFG,
        ELECTROLYTIC_LIFE,
        POOL_LID_STATE,
        HOT_PUMP_STATE,
        GAS_SWITCH_V,

        IC_ID1 = 0x800,
        IC_ID2,
        IC_ID3,
        IC_ID4,
        IC_ID5,
        IC_ID6,

    };
    Q_ENUM(input_registers_item)

    enum holding_registers_item
    {
        MODE = 0,
        ADDR,
        BEST_ORP,
        BEST_PH,
        POOL_SIZE,
        TIMER_EN,
        OPEN_TIMER1,
        CLOSE_TIMER1,
        OPEN_TIMER2,
        CLOSE_TIMER2,
        ACID_ML_DAY,
        MANUAL_POWER,
        LOCAL_TIME,
        SALT_TYPE,
        DIR_CHANGE_TIME,
        INVERTER_WATER_PUMP,
        EXT_DEV1,
        EXT_DEV2,
        BOOST,
        FA_PASSWORD = 0x800,
        FA_CONTROL_MODE_DIY,
        FA_ELECTROLYTIC,
    };
    Q_ENUM(holding_registers_item)

    struct data_item_t
    {
        modbus_dataTypes type;
        QStringList items;
        int number;     //数量
    };
    struct input_register_display_t
    {
        QLabel* lb;
        QSpinBox* sp;
    };
    struct discrete_input_display_t
    {
        QLabel* lb;
        QSpinBox* sp;
    };

    struct holding_register_display_t
    {
        QLabel* lb;
        QSpinBox* sp;
        QTimeEdit* te;
    };

private slots:
    void on_pb_openPort_clicked();

    void on_cb_modbusDataType_currentIndexChanged(int index);

    void on_pb_modbusRead_clicked();

    void on_cb_autoRead_checkStateChanged(const Qt::CheckState &arg1);

    void on_auto_read_timeout(void);

    void on_pb_modbusWrite_clicked();

    void on_pb_uidRead_clicked();

    void on_pb_cfgWrite_clicked();

private:
    void Calc_PassWord(void);
    void Fill_SerialPort(void);
    void modbus_item_init(void);
    void modbus_item_type_init(modbus_dataTypes type);
    void modbus_item_coils_init(void);
    void modbus_item_discrete_inputs_init(void);
    void modbus_item_input_registers_init(void);
    void modbus_item_holding_registers_init(void);
    void modbus_operate_display(modbus_dataTypes type);
    void On_Write_Reply();
    void Read_DiscreteInputs(void);
    void On_DiscreteInputs_Ready(void);
    void Read_Coils(void);
    void On_Coils_Ready(void);
    void Read_InputRegisters(void);
    void On_InputRegisters_Ready(void);
    void Read_HoldingRegisters(void);
    void On_HoldingRegisters_Ready(void);
    void Write_HoldingRegisters(void);

private:
    qint16 m_discreteInputsReadCount;
    data_item_t m_dataItems[4];
    QList<input_register_display_t> m_inputRegisterDisplay;
    QList<discrete_input_display_t> m_discreteInputDisplay;
    QList<holding_register_display_t> m_holdingRegisterDisplay;
    uint16_t m_password;
    uint16_t m_icid[6];
    uint32_t m_crc32Icid;
    uint16_t m_readNums;
    uint16_t m_writeNums;
    const int inputFaNum = IC_ID6 - IC_ID1 + 1;
    const int holdingFaNum = FA_ELECTROLYTIC - FA_PASSWORD + 1;
};
#endif // WIDGET_H
